#pragma once
#include <stdio.h>
#include <string>
#include <vector>
#include "FloatLList.h"

using namespace std;

class ModelLList
{
	typedef struct Vertex{
		float x, y, z;
	};

	typedef struct ModelList
	{
		int id;
		ModelList* Next;

		float rotationAngleX,rotationAngleY,rotationAngleZ;
		Vertex transformation;
		Vertex pivot;
		Vertex localAxis;
		Vertex localCenter;

		int hierarchy;
		vector<int> children;
		

		bool selected;
		bool root;

		string matName;
		string name;
		int matId;
		FloatLList *verticles;
		FloatLList *faces;
		//FloatLList *normal;
		FloatLList *textCoords;
		vector<Vertex> normals;

		ModelList()
		{
			transformation.x = 0; transformation.y = 0; transformation.z = 0;
			pivot.x = 0; pivot.y = 0; pivot.z = 0;
			localAxis.x = 0; localAxis.y = 0; localAxis.z = 0;
			localCenter.x = 0; localCenter.y = 0; localCenter.z = 0;
			rotationAngleX=rotationAngleY=rotationAngleZ=0;
			hierarchy = -2;
			Next=NULL;
			selected = false;
			root = false;
			name = "";
			matName = "";
			faces = new FloatLList();
			verticles = new FloatLList();
			textCoords = new FloatLList();
			id=0;
			matId = 0;
		}
	};

	typedef ModelList* MListPtr;
	
public:
	ModelList* Head;
	ModelList* Tail;
	ModelList* CurrentPtr;

	ModelLList()
	{
		Head = new ModelList;
		Tail = Head;
		CurrentPtr = Head;
	};

	void AddANode()
	{
		Tail->Next = new ModelList;
		Tail->Next->id = Tail->id + 1;
		Tail = Tail->Next;
		CurrentPtr = Tail;
	};

	MListPtr Previous(MListPtr index)
	{
		MListPtr temp=Head;
		if(index==Head) //special case, index IS the head :)
		{
			return Head;
		}

		while(temp->Next != index)
		{
			temp=temp->Next;
		}

		return temp;
	};
	Vertex GenerateNormal(Vertex A, Vertex B, Vertex C)
	{
		float Px,Py,Pz,Qx,Qy,Qz;
		float d,Nx,Ny,Nz;
		Px = B.x - A.x;
		Py = B.y - A.y;
		Pz = B.z - A.z;
		Qx = C.x - A.x;
		Qy = C.y - A.y;
		Qz = C.z - A.z;
		Nx=(Qz*Py)-(Qy*Pz);
		Ny=(Qx*Pz)-(Qz*Px);
		Nz=(Qy*Px)-(Qx*Py);
		d=sqrt(((Nx*Nx)+(Ny*Ny)+(Nz*Nz)));

		Vertex normal = { Nx/d, Ny/d, Nz/d };

		return normal;	
	}
	void MakeNormals()
	{
		CurrentPtr->faces->CurrentPtr = CurrentPtr->faces->Head->Next;
		CurrentPtr->textCoords->CurrentPtr = CurrentPtr->textCoords->Head->Next;

		Vertex noVert;
		Vertex A, B, C, N;
		int nr = 0;
		do
		{
			nr++;
			noVert.x = CurrentPtr->faces->CurrentPtr->sData;
			CurrentPtr->faces->Advance();
			noVert.y = CurrentPtr->faces->CurrentPtr->sData;
			CurrentPtr->faces->Advance();
			noVert.z = CurrentPtr->faces->CurrentPtr->sData;
			CurrentPtr->faces->Advance();

			A.x = CurrentPtr->verticles->GetId(noVert.x*3 + 1)->fData;
			A.y = CurrentPtr->verticles->GetId(noVert.x*3 + 2)->fData;
			A.z = CurrentPtr->verticles->GetId(noVert.x*3 + 3)->fData;
			B.x = CurrentPtr->verticles->GetId(noVert.y*3 + 1)->fData;
			B.y = CurrentPtr->verticles->GetId(noVert.y*3 + 2)->fData;
			B.z = CurrentPtr->verticles->GetId(noVert.y*3 + 3)->fData;
			C.x = CurrentPtr->verticles->GetId(noVert.z*3 + 1)->fData;
			C.y = CurrentPtr->verticles->GetId(noVert.z*3 + 2)->fData;
			C.z = CurrentPtr->verticles->GetId(noVert.z*3 + 3)->fData;
			N = GenerateNormal(A, B, C);

			CurrentPtr->normals.push_back(N);

		}while(CurrentPtr->faces->CurrentPtr != CurrentPtr->faces->Tail->Next);
	}

	void Advance()
	{
		CurrentPtr=CurrentPtr->Next;
	};

	void Rewind()
	{
		if(CurrentPtr != Head)
		{
			CurrentPtr=Previous(CurrentPtr);
		}
	};

	ModelList* GetId(int _id)
	{
		if(CurrentPtr->id == _id)
			return CurrentPtr;

		CurrentPtr = Head;
		do
		{
			Advance();
		}while(CurrentPtr->id != _id && CurrentPtr != Tail);

		return CurrentPtr;
	}

	void DeleteANode(MListPtr corpse)
	{
		MListPtr temp;

		if(corpse == Head) //case 1 corpse = Head
		{
			temp=Head;
			Head=Head->Next;
			delete temp;
		}
		else if(corpse == Tail) //case 2 corpse is at the end
		{
			temp = Tail;
			Tail=Previous(Tail);
			Tail->Next=NULL;
			delete temp;
		}
		else //case 3 corpse is in middle somewhere
		{
			temp=Previous(corpse);
			temp->Next=corpse->Next;
			delete corpse;
		}

		CurrentPtr=Head; //Reset the class tempptr
	};

	~ModelLList()
	{
		MListPtr temp = Head;
		CurrentPtr = Head;

		while(CurrentPtr != NULL)
		{
			CurrentPtr = CurrentPtr->Next;
			delete temp;
			temp=CurrentPtr;
		}
	};

};